#include "gtkadjustment.h"
#include "gtkadjustmentprivate.h"
#include "gtkbindings.h"
+#include "gtkcsscustomgadgetprivate.h"
#include "gtkdnd.h"
#include "gtkintl.h"
#include "gtkmain.h"
GtkWidget *hscrollbar;
GtkWidget *vscrollbar;
+ GtkCssGadget *gadget;
GtkCssNode *overshoot_node[4];
GtkCssNode *undershoot_node[4];
static void gtk_scrolled_window_relative_allocation(GtkWidget *widget,
GtkAllocation *allocation);
+static void gtk_scrolled_window_inner_allocation (GtkWidget *widget,
+ GtkAllocation *rect);
+static void gtk_scrolled_window_allocate_scrollbar (GtkScrolledWindow *scrolled_window,
+ GtkWidget *scrollbar,
+ GtkAllocation *allocation);
+static void gtk_scrolled_window_allocate_child (GtkScrolledWindow *swindow,
+ GtkAllocation *relative_allocation);
static void gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
gpointer data);
static void gtk_scrolled_window_adjustment_value_changed (GtkAdjustment *adjustment,
return GDK_EVENT_PROPAGATE;
}
-static void
-gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
-{
- GtkWidget *widget = GTK_WIDGET (scrolled_window);
- GtkScrolledWindowPrivate *priv;
- GtkCssNode *widget_node;
- GQuark classes[4] = {
- g_quark_from_static_string (GTK_STYLE_CLASS_LEFT),
- g_quark_from_static_string (GTK_STYLE_CLASS_RIGHT),
- g_quark_from_static_string (GTK_STYLE_CLASS_TOP),
- g_quark_from_static_string (GTK_STYLE_CLASS_BOTTOM),
- };
- gint i;
-
- scrolled_window->priv = priv =
- gtk_scrolled_window_get_instance_private (scrolled_window);
-
- gtk_widget_set_has_window (widget, TRUE);
- gtk_widget_set_can_focus (widget, TRUE);
-
- /* Instantiated by gtk_scrolled_window_set_[hv]adjustment
- * which are both construct properties
- */
- priv->hscrollbar = NULL;
- priv->vscrollbar = NULL;
- priv->hscrollbar_policy = GTK_POLICY_AUTOMATIC;
- priv->vscrollbar_policy = GTK_POLICY_AUTOMATIC;
- priv->hscrollbar_visible = FALSE;
- priv->vscrollbar_visible = FALSE;
- priv->focus_out = FALSE;
- priv->window_placement = GTK_CORNER_TOP_LEFT;
- priv->min_content_width = -1;
- priv->min_content_height = -1;
-
- priv->overlay_scrolling = TRUE;
-
- priv->drag_gesture = gtk_gesture_drag_new (widget);
- gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (priv->drag_gesture), TRUE);
- g_signal_connect_swapped (priv->drag_gesture, "drag-begin",
- G_CALLBACK (scrolled_window_drag_begin_cb),
- scrolled_window);
- g_signal_connect_swapped (priv->drag_gesture, "drag-update",
- G_CALLBACK (scrolled_window_drag_update_cb),
- scrolled_window);
- g_signal_connect_swapped (priv->drag_gesture, "end",
- G_CALLBACK (scrolled_window_drag_end_cb),
- scrolled_window);
-
- priv->pan_gesture = gtk_gesture_pan_new (widget, GTK_ORIENTATION_VERTICAL);
- gtk_gesture_group (priv->pan_gesture, priv->drag_gesture);
- gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (priv->pan_gesture), TRUE);
-
- priv->swipe_gesture = gtk_gesture_swipe_new (widget);
- gtk_gesture_group (priv->swipe_gesture, priv->drag_gesture);
- gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (priv->swipe_gesture), TRUE);
- g_signal_connect_swapped (priv->swipe_gesture, "swipe",
- G_CALLBACK (scrolled_window_swipe_cb),
- scrolled_window);
- priv->long_press_gesture = gtk_gesture_long_press_new (widget);
- gtk_gesture_group (priv->long_press_gesture, priv->drag_gesture);
- gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (priv->long_press_gesture), TRUE);
- g_signal_connect_swapped (priv->long_press_gesture, "pressed",
- G_CALLBACK (scrolled_window_long_press_cb),
- scrolled_window);
- g_signal_connect_swapped (priv->long_press_gesture, "cancelled",
- G_CALLBACK (scrolled_window_long_press_cancelled_cb),
- scrolled_window);
-
- priv->scroll_history = g_array_new (FALSE, FALSE, sizeof (ScrollHistoryElem));
-
- gtk_scrolled_window_set_kinetic_scrolling (scrolled_window, TRUE);
- gtk_scrolled_window_set_capture_button_press (scrolled_window, TRUE);
-
- _gtk_widget_set_captured_event_handler (widget, captured_event_cb);
-
- widget_node = gtk_widget_get_css_node (widget);
- for (i = 0; i < 4; i++)
- {
- priv->overshoot_node[i] = gtk_css_node_new ();
- gtk_css_node_set_name (priv->overshoot_node[i], I_("overshoot"));
- gtk_css_node_add_class (priv->overshoot_node[i], classes[i]);
- gtk_css_node_set_parent (priv->overshoot_node[i], widget_node);
- gtk_css_node_set_state (priv->overshoot_node[i], gtk_css_node_get_state (widget_node));
- g_object_unref (priv->overshoot_node[i]);
-
- priv->undershoot_node[i] = gtk_css_node_new ();
- gtk_css_node_set_name (priv->undershoot_node[i], I_("undershoot"));
- gtk_css_node_add_class (priv->undershoot_node[i], classes[i]);
- gtk_css_node_set_parent (priv->undershoot_node[i], widget_node);
- gtk_css_node_set_state (priv->undershoot_node[i], gtk_css_node_get_state (widget_node));
- g_object_unref (priv->undershoot_node[i]);
- }
-}
-
-/**
- * gtk_scrolled_window_new:
- * @hadjustment: (allow-none): horizontal adjustment
- * @vadjustment: (allow-none): vertical adjustment
- *
- * Creates a new scrolled window.
+/*
+ * _gtk_scrolled_window_get_spacing:
+ * @scrolled_window: a scrolled window
*
- * The two arguments are the scrolled window’s adjustments; these will be
- * shared with the scrollbars and the child widget to keep the bars in sync
- * with the child. Usually you want to pass %NULL for the adjustments, which
- * will cause the scrolled window to create them for you.
+ * Gets the spacing between the scrolled window’s scrollbars and
+ * the scrolled widget. Used by GtkCombo
*
- * Returns: a new scrolled window
+ * Returns: the spacing, in pixels.
*/
-GtkWidget*
-gtk_scrolled_window_new (GtkAdjustment *hadjustment,
- GtkAdjustment *vadjustment)
+static gint
+_gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window)
{
- GtkWidget *scrolled_window;
+ GtkScrolledWindowClass *class;
- if (hadjustment)
- g_return_val_if_fail (GTK_IS_ADJUSTMENT (hadjustment), NULL);
+ g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), 0);
- if (vadjustment)
- g_return_val_if_fail (GTK_IS_ADJUSTMENT (vadjustment), NULL);
+ class = GTK_SCROLLED_WINDOW_GET_CLASS (scrolled_window);
- scrolled_window = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
- "hadjustment", hadjustment,
- "vadjustment", vadjustment,
- NULL);
+ if (class->scrollbar_spacing >= 0)
+ return class->scrollbar_spacing;
+ else
+ {
+ gint scrollbar_spacing;
- return scrolled_window;
+ gtk_widget_style_get (GTK_WIDGET (scrolled_window),
+ "scrollbar-spacing", &scrollbar_spacing,
+ NULL);
+
+ return scrollbar_spacing;
+ }
}
-/**
- * gtk_scrolled_window_set_hadjustment:
- * @scrolled_window: a #GtkScrolledWindow
- * @hadjustment: horizontal scroll adjustment
- *
- * Sets the #GtkAdjustment for the horizontal scrollbar.
- */
-void
-gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
- GtkAdjustment *hadjustment)
+static void
+gtk_scrolled_window_allocate (GtkCssGadget *gadget,
+ const GtkAllocation *allocation,
+ int baseline,
+ GtkAllocation *out_clip,
+ gpointer data)
{
- GtkScrolledWindowPrivate *priv;
+ GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
+ GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
+ GtkScrolledWindowPrivate *priv = scrolled_window->priv;
GtkBin *bin;
+ GtkAllocation relative_allocation;
+ GtkAllocation child_allocation;
GtkWidget *child;
-
- g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
- if (hadjustment)
- g_return_if_fail (GTK_IS_ADJUSTMENT (hadjustment));
- else
- hadjustment = (GtkAdjustment*) g_object_new (GTK_TYPE_ADJUSTMENT, NULL);
+ gint sb_spacing;
+ gint sb_width;
+ gint sb_height;
bin = GTK_BIN (scrolled_window);
- priv = scrolled_window->priv;
-
- if (!priv->hscrollbar)
- {
- priv->hscrollbar = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, hadjustment);
- gtk_widget_set_parent (priv->hscrollbar, GTK_WIDGET (scrolled_window));
- g_object_ref (priv->hscrollbar);
- gtk_widget_show (priv->hscrollbar);
- update_scrollbar_positions (scrolled_window);
- }
- else
- {
- GtkAdjustment *old_adjustment;
+ /* Get possible scrollbar dimensions */
+ sb_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
+ gtk_widget_get_preferred_height (priv->hscrollbar, &sb_height, NULL);
+ gtk_widget_get_preferred_width (priv->vscrollbar, &sb_width, NULL);
- old_adjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
- if (old_adjustment == hadjustment)
- return;
+ if (priv->hscrollbar_policy == GTK_POLICY_ALWAYS)
+ priv->hscrollbar_visible = TRUE;
+ else if (priv->hscrollbar_policy == GTK_POLICY_NEVER ||
+ priv->hscrollbar_policy == GTK_POLICY_EXTERNAL)
+ priv->hscrollbar_visible = FALSE;
- g_signal_handlers_disconnect_by_func (old_adjustment,
- gtk_scrolled_window_adjustment_changed,
- scrolled_window);
- gtk_adjustment_enable_animation (old_adjustment, NULL, 0);
- gtk_range_set_adjustment (GTK_RANGE (priv->hscrollbar), hadjustment);
- }
- hadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
- g_signal_connect (hadjustment,
- "changed",
- G_CALLBACK (gtk_scrolled_window_adjustment_changed),
- scrolled_window);
- g_signal_connect (hadjustment,
- "value-changed",
- G_CALLBACK (gtk_scrolled_window_adjustment_value_changed),
- scrolled_window);
- gtk_scrolled_window_adjustment_changed (hadjustment, scrolled_window);
- gtk_scrolled_window_adjustment_value_changed (hadjustment, scrolled_window);
+ if (priv->vscrollbar_policy == GTK_POLICY_ALWAYS)
+ priv->vscrollbar_visible = TRUE;
+ else if (priv->vscrollbar_policy == GTK_POLICY_NEVER ||
+ priv->vscrollbar_policy == GTK_POLICY_EXTERNAL)
+ priv->vscrollbar_visible = FALSE;
child = gtk_bin_get_child (bin);
- if (GTK_IS_SCROLLABLE (child))
- gtk_scrollable_set_hadjustment (GTK_SCROLLABLE (child), hadjustment);
+ if (child && gtk_widget_get_visible (child))
+ {
+ gint child_scroll_width;
+ gint child_scroll_height;
+ GtkScrollablePolicy hscroll_policy;
+ GtkScrollablePolicy vscroll_policy;
+ gboolean previous_hvis;
+ gboolean previous_vvis;
+ guint count = 0;
- if (gtk_scrolled_window_should_animate (scrolled_window))
- gtk_adjustment_enable_animation (hadjustment, gtk_widget_get_frame_clock (GTK_WIDGET (scrolled_window)), ANIMATION_DURATION);
- g_object_notify_by_pspec (G_OBJECT (scrolled_window), properties[PROP_HADJUSTMENT]);
-}
+ hscroll_policy = GTK_IS_SCROLLABLE (child)
+ ? gtk_scrollable_get_hscroll_policy (GTK_SCROLLABLE (child))
+ : GTK_SCROLL_MINIMUM;
+ vscroll_policy = GTK_IS_SCROLLABLE (child)
+ ? gtk_scrollable_get_vscroll_policy (GTK_SCROLLABLE (child))
+ : GTK_SCROLL_MINIMUM;
-/**
- * gtk_scrolled_window_set_vadjustment:
- * @scrolled_window: a #GtkScrolledWindow
- * @vadjustment: vertical scroll adjustment
- *
- * Sets the #GtkAdjustment for the vertical scrollbar.
- */
-void
-gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
- GtkAdjustment *vadjustment)
-{
- GtkScrolledWindowPrivate *priv;
- GtkBin *bin;
- GtkWidget *child;
+ /* Determine scrollbar visibility first via hfw apis */
+ if (gtk_widget_get_request_mode (child) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
+ {
+ if (hscroll_policy == GTK_SCROLL_MINIMUM)
+ gtk_widget_get_preferred_width (child, &child_scroll_width, NULL);
+ else
+ gtk_widget_get_preferred_width (child, NULL, &child_scroll_width);
- g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
- if (vadjustment)
- g_return_if_fail (GTK_IS_ADJUSTMENT (vadjustment));
+ if (priv->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
+ {
+ /* First try without a vertical scrollbar if the content will fit the height
+ * given the extra width of the scrollbar */
+ if (vscroll_policy == GTK_SCROLL_MINIMUM)
+ gtk_widget_get_preferred_height_for_width (child,
+ MAX (allocation->width, child_scroll_width),
+ &child_scroll_height, NULL);
+ else
+ gtk_widget_get_preferred_height_for_width (child,
+ MAX (allocation->width, child_scroll_width),
+ NULL, &child_scroll_height);
+
+ if (priv->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
+ {
+ /* Does the content height fit the allocation height ? */
+ priv->vscrollbar_visible = child_scroll_height > allocation->height;
+
+ /* Does the content width fit the allocation with minus a possible scrollbar ? */
+ priv->hscrollbar_visible =
+ child_scroll_width > allocation->width -
+ (priv->vscrollbar_visible && !priv->use_indicators ? sb_width + sb_spacing : 0);
+
+ /* Now that we've guessed the hscrollbar, does the content height fit
+ * the possible new allocation height ?
+ */
+ priv->vscrollbar_visible =
+ child_scroll_height > allocation->height -
+ (priv->hscrollbar_visible && !priv->use_indicators ? sb_height + sb_spacing : 0);
+
+ /* Now that we've guessed the vscrollbar, does the content width fit
+ * the possible new allocation width ?
+ */
+ priv->hscrollbar_visible =
+ child_scroll_width > allocation->width -
+ (priv->vscrollbar_visible && !priv->use_indicators ? sb_width + sb_spacing : 0);
+ }
+ else /* priv->hscrollbar_policy != GTK_POLICY_AUTOMATIC */
+ {
+ priv->hscrollbar_visible = policy_may_be_visible (priv->hscrollbar_policy);
+ priv->vscrollbar_visible = child_scroll_height > allocation->height -
+ (priv->hscrollbar_visible && !priv->use_indicators ? sb_height + sb_spacing : 0);
+ }
+ }
+ else /* priv->vscrollbar_policy != GTK_POLICY_AUTOMATIC */
+ {
+ priv->vscrollbar_visible = policy_may_be_visible (priv->vscrollbar_policy);
+
+ if (priv->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
+ priv->hscrollbar_visible =
+ child_scroll_width > allocation->width -
+ (priv->vscrollbar_visible && !priv->use_indicators ? 0 : sb_width + sb_spacing);
+ else
+ priv->hscrollbar_visible = policy_may_be_visible (priv->hscrollbar_policy);
+ }
+ }
+ else /* GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT */
+ {
+ if (vscroll_policy == GTK_SCROLL_MINIMUM)
+ gtk_widget_get_preferred_height (child, &child_scroll_height, NULL);
+ else
+ gtk_widget_get_preferred_height (child, NULL, &child_scroll_height);
+
+ if (priv->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
+ {
+ /* First try without a horizontal scrollbar if the content will fit the width
+ * given the extra height of the scrollbar */
+ if (hscroll_policy == GTK_SCROLL_MINIMUM)
+ gtk_widget_get_preferred_width_for_height (child,
+ MAX (allocation->height, child_scroll_height),
+ &child_scroll_width, NULL);
+ else
+ gtk_widget_get_preferred_width_for_height (child,
+ MAX (allocation->height, child_scroll_height),
+ NULL, &child_scroll_width);
+
+ if (priv->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
+ {
+ /* Does the content width fit the allocation width ? */
+ priv->hscrollbar_visible = child_scroll_width > allocation->width;
+
+ /* Does the content height fit the allocation with minus a possible scrollbar ? */
+ priv->vscrollbar_visible =
+ child_scroll_height > allocation->height -
+ (priv->hscrollbar_visible && !priv->use_indicators ? sb_height + sb_spacing : 0);
+
+ /* Now that we've guessed the vscrollbar, does the content width fit
+ * the possible new allocation width ?
+ */
+ priv->hscrollbar_visible =
+ child_scroll_width > allocation->width -
+ (priv->vscrollbar_visible && !priv->use_indicators ? sb_width + sb_spacing : 0);
+
+ /* Now that we've guessed the hscrollbar, does the content height fit
+ * the possible new allocation height ?
+ */
+ priv->vscrollbar_visible =
+ child_scroll_height > allocation->height -
+ (priv->hscrollbar_visible && !priv->use_indicators ? sb_height + sb_spacing : 0);
+ }
+ else /* priv->vscrollbar_policy != GTK_POLICY_AUTOMATIC */
+ {
+ priv->vscrollbar_visible = policy_may_be_visible (priv->vscrollbar_policy);
+ priv->hscrollbar_visible = child_scroll_width > allocation->width -
+ (priv->vscrollbar_visible && !priv->use_indicators ? sb_width + sb_spacing : 0);
+ }
+ }
+ else /* priv->hscrollbar_policy != GTK_POLICY_AUTOMATIC */
+ {
+ priv->hscrollbar_visible = policy_may_be_visible (priv->hscrollbar_policy);
+
+ if (priv->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
+ priv->vscrollbar_visible =
+ child_scroll_height > allocation->height -
+ (priv->hscrollbar_visible && !priv->use_indicators ? sb_height + sb_spacing : 0);
+ else
+ priv->vscrollbar_visible = policy_may_be_visible (priv->vscrollbar_policy);
+ }
+ }
+
+ /* Now after guessing scrollbar visibility; fall back on the allocation loop which
+ * observes the adjustments to detect scrollbar visibility and also avoids
+ * infinite recursion
+ */
+ do
+ {
+ previous_hvis = priv->hscrollbar_visible;
+ previous_vvis = priv->vscrollbar_visible;
+ gtk_scrolled_window_allocate_child (scrolled_window, &relative_allocation);
+
+ /* Explicitly force scrollbar visibility checks.
+ *
+ * Since we make a guess above, the child might not decide to update the adjustments
+ * if they logically did not change since the last configuration
+ */
+ if (priv->hscrollbar)
+ gtk_scrolled_window_adjustment_changed
+ (gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)), scrolled_window);
+
+ if (priv->vscrollbar)
+ gtk_scrolled_window_adjustment_changed
+ (gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)), scrolled_window);
+
+ /* If, after the first iteration, the hscrollbar and the
+ * vscrollbar flip visiblity... or if one of the scrollbars flip
+ * on each itteration indefinitly/infinitely, then we just need both
+ * at this size.
+ */
+ if ((count &&
+ previous_hvis != priv->hscrollbar_visible &&
+ previous_vvis != priv->vscrollbar_visible) || count > 3)
+ {
+ priv->hscrollbar_visible = TRUE;
+ priv->vscrollbar_visible = TRUE;
+
+ gtk_scrolled_window_allocate_child (scrolled_window, &relative_allocation);
+
+ break;
+ }
+
+ count++;
+ }
+ while (previous_hvis != priv->hscrollbar_visible ||
+ previous_vvis != priv->vscrollbar_visible);
+ }
+ else
+ {
+ priv->hscrollbar_visible = priv->hscrollbar_policy == GTK_POLICY_ALWAYS;
+ priv->vscrollbar_visible = priv->vscrollbar_policy == GTK_POLICY_ALWAYS;
+ gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
+ }
+
+ gtk_widget_set_child_visible (priv->hscrollbar, priv->hscrollbar_visible);
+ if (priv->hscrollbar_visible)
+ {
+ gtk_scrolled_window_allocate_scrollbar (scrolled_window,
+ priv->hscrollbar,
+ &child_allocation);
+ if (priv->use_indicators)
+ {
+ gdk_window_move_resize (priv->hindicator.window,
+ child_allocation.x,
+ child_allocation.y,
+ child_allocation.width,
+ child_allocation.height);
+ child_allocation.x = 0;
+ child_allocation.y = 0;
+ }
+ gtk_widget_size_allocate (priv->hscrollbar, &child_allocation);
+ }
+
+ gtk_widget_set_child_visible (priv->vscrollbar, priv->vscrollbar_visible);
+ if (priv->vscrollbar_visible)
+ {
+ gtk_scrolled_window_allocate_scrollbar (scrolled_window,
+ priv->vscrollbar,
+ &child_allocation);
+ if (priv->use_indicators)
+ {
+ gdk_window_move_resize (priv->vindicator.window,
+ child_allocation.x,
+ child_allocation.y,
+ child_allocation.width,
+ child_allocation.height);
+ child_allocation.x = 0;
+ child_allocation.y = 0;
+ }
+ gtk_widget_size_allocate (priv->vscrollbar, &child_allocation);
+ }
+
+ gtk_scrolled_window_check_attach_pan_gesture (scrolled_window);
+}
+
+static void
+gtk_scrolled_window_measure (GtkCssGadget *gadget,
+ GtkOrientation orientation,
+ int for_size,
+ int *minimum_size,
+ int *natural_size,
+ int *minimum_baseline,
+ int *natural_baseline,
+ gpointer data)
+{
+ GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
+ GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
+ GtkScrolledWindowPrivate *priv = scrolled_window->priv;
+ GtkBin *bin = GTK_BIN (scrolled_window);
+ gint extra_width;
+ gint extra_height;
+ gint scrollbar_spacing;
+ GtkRequisition hscrollbar_requisition;
+ GtkRequisition vscrollbar_requisition;
+ GtkRequisition minimum_req, natural_req;
+ GtkWidget *child;
+ gint min_child_size, nat_child_size;
+
+ scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
+
+ extra_width = 0;
+ extra_height = 0;
+ minimum_req.width = 0;
+ minimum_req.height = 0;
+ natural_req.width = 0;
+ natural_req.height = 0;
+
+ gtk_widget_get_preferred_size (priv->hscrollbar,
+ &hscrollbar_requisition, NULL);
+ gtk_widget_get_preferred_size (priv->vscrollbar,
+ &vscrollbar_requisition, NULL);
+
+ child = gtk_bin_get_child (bin);
+ if (child && gtk_widget_get_visible (child))
+ {
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ gtk_widget_get_preferred_width (child,
+ &min_child_size,
+ &nat_child_size);
+
+ if (priv->hscrollbar_policy == GTK_POLICY_NEVER)
+ {
+ minimum_req.width += min_child_size;
+ natural_req.width += nat_child_size;
+ }
+ else
+ {
+ if (priv->min_content_width >= 0)
+ {
+ minimum_req.width = MAX (minimum_req.width, priv->min_content_width);
+ natural_req.width = MAX (natural_req.width, priv->min_content_width);
+ extra_width = -1;
+ }
+ else if (policy_may_be_visible (priv->vscrollbar_policy) && !priv->use_indicators)
+ {
+ minimum_req.width += vscrollbar_requisition.width;
+ natural_req.width += vscrollbar_requisition.width;
+ }
+ }
+ }
+ else /* GTK_ORIENTATION_VERTICAL */
+ {
+ gtk_widget_get_preferred_height (child,
+ &min_child_size,
+ &nat_child_size);
+
+ if (priv->vscrollbar_policy == GTK_POLICY_NEVER)
+ {
+ minimum_req.height += min_child_size;
+ natural_req.height += nat_child_size;
+ }
+ else
+ {
+ if (priv->min_content_height >= 0)
+ {
+ minimum_req.height = MAX (minimum_req.height, priv->min_content_height);
+ natural_req.height = MAX (natural_req.height, priv->min_content_height);
+ extra_height = -1;
+ }
+ else if (policy_may_be_visible (priv->vscrollbar_policy) && !priv->use_indicators)
+ {
+ minimum_req.height += vscrollbar_requisition.height;
+ natural_req.height += vscrollbar_requisition.height;
+ }
+ }
+ }
+ }
+
+ if (policy_may_be_visible (priv->hscrollbar_policy) && !priv->use_indicators)
+ {
+ minimum_req.width = MAX (minimum_req.width, hscrollbar_requisition.width);
+ natural_req.width = MAX (natural_req.width, hscrollbar_requisition.width);
+ if (!extra_height || priv->hscrollbar_policy == GTK_POLICY_ALWAYS)
+ extra_height = scrollbar_spacing + hscrollbar_requisition.height;
+ }
+
+ if (policy_may_be_visible (priv->vscrollbar_policy) && !priv->use_indicators)
+ {
+ minimum_req.height = MAX (minimum_req.height, vscrollbar_requisition.height);
+ natural_req.height = MAX (natural_req.height, vscrollbar_requisition.height);
+ if (!extra_width || priv->vscrollbar_policy == GTK_POLICY_ALWAYS)
+ extra_width = scrollbar_spacing + vscrollbar_requisition.width;
+ }
+
+ minimum_req.width += MAX (0, extra_width);
+ minimum_req.height += MAX (0, extra_height);
+ natural_req.width += MAX (0, extra_width);
+ natural_req.height += MAX (0, extra_height);
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ *minimum_size = minimum_req.width;
+ *natural_size = natural_req.width;
+ }
+ else
+ {
+ *minimum_size = minimum_req.height;
+ *natural_size = natural_req.height;
+ }
+}
+
+static void
+gtk_scrolled_window_draw_scrollbars_junction (GtkScrolledWindow *scrolled_window,
+ cairo_t *cr)
+{
+ GtkScrolledWindowPrivate *priv = scrolled_window->priv;
+ GtkWidget *widget = GTK_WIDGET (scrolled_window);
+ GtkAllocation content_allocation, hscr_allocation, vscr_allocation;
+ GtkStyleContext *context;
+ GdkRectangle junction_rect;
+ gboolean is_rtl;
+
+ is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
+ gtk_widget_get_allocation (GTK_WIDGET (priv->hscrollbar), &hscr_allocation);
+ gtk_widget_get_allocation (GTK_WIDGET (priv->vscrollbar), &vscr_allocation);
+ gtk_css_gadget_get_content_allocation (priv->gadget, &content_allocation,
+ NULL);
+
+ junction_rect.x = content_allocation.x;
+ junction_rect.y = content_allocation.y;
+ junction_rect.width = vscr_allocation.width;
+ junction_rect.height = hscr_allocation.height;
+
+ if ((is_rtl &&
+ (priv->window_placement == GTK_CORNER_TOP_RIGHT ||
+ priv->window_placement == GTK_CORNER_BOTTOM_RIGHT)) ||
+ (!is_rtl &&
+ (priv->window_placement == GTK_CORNER_TOP_LEFT ||
+ priv->window_placement == GTK_CORNER_BOTTOM_LEFT)))
+ junction_rect.x += hscr_allocation.width;
+
+ if (priv->window_placement == GTK_CORNER_TOP_LEFT ||
+ priv->window_placement == GTK_CORNER_TOP_RIGHT)
+ junction_rect.y += vscr_allocation.height;
+
+ context = gtk_widget_get_style_context (widget);
+ gtk_style_context_save_named (context, "junction");
+
+ gtk_render_background (context, cr,
+ junction_rect.x, junction_rect.y,
+ junction_rect.width, junction_rect.height);
+ gtk_render_frame (context, cr,
+ junction_rect.x, junction_rect.y,
+ junction_rect.width, junction_rect.height);
+
+ gtk_style_context_restore (context);
+}
+
+static void
+gtk_scrolled_window_draw_overshoot (GtkScrolledWindow *scrolled_window,
+ cairo_t *cr)
+{
+ GtkScrolledWindowPrivate *priv = scrolled_window->priv;
+ GtkWidget *widget = GTK_WIDGET (scrolled_window);
+ gint overshoot_x, overshoot_y;
+ GtkStyleContext *context;
+ GdkRectangle rect;
+
+ if (!_gtk_scrolled_window_get_overshoot (scrolled_window, &overshoot_x, &overshoot_y))
+ return;
+
+ context = gtk_widget_get_style_context (widget);
+ gtk_scrolled_window_inner_allocation (widget, &rect);
+
+ overshoot_x = CLAMP (overshoot_x, - MAX_OVERSHOOT_DISTANCE, MAX_OVERSHOOT_DISTANCE);
+ overshoot_y = CLAMP (overshoot_y, - MAX_OVERSHOOT_DISTANCE, MAX_OVERSHOOT_DISTANCE);
+
+ if (overshoot_x > 0)
+ {
+ gtk_style_context_save_to_node (context, priv->overshoot_node[GTK_POS_RIGHT]);
+ gtk_render_background (context, cr, rect.x + rect.width - overshoot_x, rect.y, overshoot_x, rect.height);
+ gtk_render_frame (context, cr, rect.x + rect.width - overshoot_x, rect.y, overshoot_x, rect.height);
+ gtk_style_context_restore (context);
+ }
+ else if (overshoot_x < 0)
+ {
+ gtk_style_context_save_to_node (context, priv->overshoot_node[GTK_POS_LEFT]);
+ gtk_render_background (context, cr, rect.x, rect.y, -overshoot_x, rect.height);
+ gtk_render_frame (context, cr, rect.x, rect.y, -overshoot_x, rect.height);
+ gtk_style_context_restore (context);
+ }
+
+ if (overshoot_y > 0)
+ {
+ gtk_style_context_save_to_node (context, priv->overshoot_node[GTK_POS_BOTTOM]);
+ gtk_render_background (context, cr, rect.x, rect.y + rect.height - overshoot_y, rect.width, overshoot_y);
+ gtk_render_frame (context, cr, rect.x, rect.y + rect.height - overshoot_y, rect.width, overshoot_y);
+ gtk_style_context_restore (context);
+ }
+ else if (overshoot_y < 0)
+ {
+ gtk_style_context_save_to_node (context, priv->overshoot_node[GTK_POS_TOP]);
+ gtk_render_background (context, cr, rect.x, rect.y, rect.width, -overshoot_y);
+ gtk_render_frame (context, cr, rect.x, rect.y, rect.width, -overshoot_y);
+ gtk_style_context_restore (context);
+ }
+}
+
+static void
+gtk_scrolled_window_draw_undershoot (GtkScrolledWindow *scrolled_window,
+ cairo_t *cr)
+{
+ GtkScrolledWindowPrivate *priv = scrolled_window->priv;
+ GtkWidget *widget = GTK_WIDGET (scrolled_window);
+ GtkStyleContext *context;
+ GdkRectangle rect;
+ GtkAdjustment *adj;
+
+ context = gtk_widget_get_style_context (widget);
+ gtk_scrolled_window_inner_allocation (widget, &rect);
+
+ adj = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
+ if (gtk_adjustment_get_value (adj) < gtk_adjustment_get_upper (adj) - gtk_adjustment_get_page_size (adj))
+ {
+ gtk_style_context_save_to_node (context, priv->undershoot_node[GTK_POS_RIGHT]);
+ gtk_render_background (context, cr, rect.x + rect.width - UNDERSHOOT_SIZE, rect.y, UNDERSHOOT_SIZE, rect.height);
+ gtk_render_frame (context, cr, rect.x + rect.width - UNDERSHOOT_SIZE, rect.y, UNDERSHOOT_SIZE, rect.height);
+
+ gtk_style_context_restore (context);
+ }
+ if (gtk_adjustment_get_value (adj) > gtk_adjustment_get_lower (adj))
+ {
+ gtk_style_context_save_to_node (context, priv->undershoot_node[GTK_POS_LEFT]);
+ gtk_render_background (context, cr, rect.x, rect.y, UNDERSHOOT_SIZE, rect.height);
+ gtk_render_frame (context, cr, rect.x, rect.y, UNDERSHOOT_SIZE, rect.height);
+ gtk_style_context_restore (context);
+ }
+
+ adj = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
+ if (gtk_adjustment_get_value (adj) < gtk_adjustment_get_upper (adj) - gtk_adjustment_get_page_size (adj))
+ {
+ gtk_style_context_save_to_node (context, priv->undershoot_node[GTK_POS_BOTTOM]);
+ gtk_render_background (context, cr, rect.x, rect.y + rect.height - UNDERSHOOT_SIZE, rect.width, UNDERSHOOT_SIZE);
+ gtk_render_frame (context, cr, rect.x, rect.y + rect.height - UNDERSHOOT_SIZE, rect.width, UNDERSHOOT_SIZE);
+ gtk_style_context_restore (context);
+ }
+ if (gtk_adjustment_get_value (adj) > gtk_adjustment_get_lower (adj))
+ {
+ gtk_style_context_save_to_node (context, priv->undershoot_node[GTK_POS_TOP]);
+ gtk_render_background (context, cr, rect.x, rect.y, rect.width, UNDERSHOOT_SIZE);
+ gtk_render_frame (context, cr, rect.x, rect.y, rect.width, UNDERSHOOT_SIZE);
+ gtk_style_context_restore (context);
+ }
+}
+
+static gboolean
+gtk_scrolled_window_render (GtkCssGadget *gadget,
+ cairo_t *cr,
+ int x,
+ int y,
+ int width,
+ int height,
+ gpointer data)
+{
+ GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
+ GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
+ GtkScrolledWindowPrivate *priv = scrolled_window->priv;
+
+ if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget)))
+ {
+ if (priv->hscrollbar_visible &&
+ priv->vscrollbar_visible)
+ gtk_scrolled_window_draw_scrollbars_junction (scrolled_window, cr);
+ }
+
+ GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->draw (widget, cr);
+
+ if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget)))
+ {
+ gtk_scrolled_window_draw_undershoot (scrolled_window, cr);
+ gtk_scrolled_window_draw_overshoot (scrolled_window, cr);
+ }
+
+ return FALSE;
+}
+
+static void
+gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
+{
+ GtkWidget *widget = GTK_WIDGET (scrolled_window);
+ GtkScrolledWindowPrivate *priv;
+ GtkCssNode *widget_node;
+ GQuark classes[4] = {
+ g_quark_from_static_string (GTK_STYLE_CLASS_LEFT),
+ g_quark_from_static_string (GTK_STYLE_CLASS_RIGHT),
+ g_quark_from_static_string (GTK_STYLE_CLASS_TOP),
+ g_quark_from_static_string (GTK_STYLE_CLASS_BOTTOM),
+ };
+ gint i;
+
+ scrolled_window->priv = priv =
+ gtk_scrolled_window_get_instance_private (scrolled_window);
+
+ gtk_widget_set_has_window (widget, TRUE);
+ gtk_widget_set_can_focus (widget, TRUE);
+
+ /* Instantiated by gtk_scrolled_window_set_[hv]adjustment
+ * which are both construct properties
+ */
+ priv->hscrollbar = NULL;
+ priv->vscrollbar = NULL;
+ priv->hscrollbar_policy = GTK_POLICY_AUTOMATIC;
+ priv->vscrollbar_policy = GTK_POLICY_AUTOMATIC;
+ priv->hscrollbar_visible = FALSE;
+ priv->vscrollbar_visible = FALSE;
+ priv->focus_out = FALSE;
+ priv->window_placement = GTK_CORNER_TOP_LEFT;
+ priv->min_content_width = -1;
+ priv->min_content_height = -1;
+
+ priv->overlay_scrolling = TRUE;
+
+ priv->drag_gesture = gtk_gesture_drag_new (widget);
+ gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (priv->drag_gesture), TRUE);
+ g_signal_connect_swapped (priv->drag_gesture, "drag-begin",
+ G_CALLBACK (scrolled_window_drag_begin_cb),
+ scrolled_window);
+ g_signal_connect_swapped (priv->drag_gesture, "drag-update",
+ G_CALLBACK (scrolled_window_drag_update_cb),
+ scrolled_window);
+ g_signal_connect_swapped (priv->drag_gesture, "end",
+ G_CALLBACK (scrolled_window_drag_end_cb),
+ scrolled_window);
+
+ priv->pan_gesture = gtk_gesture_pan_new (widget, GTK_ORIENTATION_VERTICAL);
+ gtk_gesture_group (priv->pan_gesture, priv->drag_gesture);
+ gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (priv->pan_gesture), TRUE);
+
+ priv->swipe_gesture = gtk_gesture_swipe_new (widget);
+ gtk_gesture_group (priv->swipe_gesture, priv->drag_gesture);
+ gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (priv->swipe_gesture), TRUE);
+ g_signal_connect_swapped (priv->swipe_gesture, "swipe",
+ G_CALLBACK (scrolled_window_swipe_cb),
+ scrolled_window);
+ priv->long_press_gesture = gtk_gesture_long_press_new (widget);
+ gtk_gesture_group (priv->long_press_gesture, priv->drag_gesture);
+ gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (priv->long_press_gesture), TRUE);
+ g_signal_connect_swapped (priv->long_press_gesture, "pressed",
+ G_CALLBACK (scrolled_window_long_press_cb),
+ scrolled_window);
+ g_signal_connect_swapped (priv->long_press_gesture, "cancelled",
+ G_CALLBACK (scrolled_window_long_press_cancelled_cb),
+ scrolled_window);
+
+ priv->scroll_history = g_array_new (FALSE, FALSE, sizeof (ScrollHistoryElem));
+
+ gtk_scrolled_window_set_kinetic_scrolling (scrolled_window, TRUE);
+ gtk_scrolled_window_set_capture_button_press (scrolled_window, TRUE);
+
+ _gtk_widget_set_captured_event_handler (widget, captured_event_cb);
+
+ widget_node = gtk_widget_get_css_node (widget);
+ priv->gadget = gtk_css_custom_gadget_new_for_node (widget_node,
+ widget,
+ gtk_scrolled_window_measure,
+ gtk_scrolled_window_allocate,
+ gtk_scrolled_window_render,
+ NULL, NULL);
+ for (i = 0; i < 4; i++)
+ {
+ priv->overshoot_node[i] = gtk_css_node_new ();
+ gtk_css_node_set_name (priv->overshoot_node[i], I_("overshoot"));
+ gtk_css_node_add_class (priv->overshoot_node[i], classes[i]);
+ gtk_css_node_set_parent (priv->overshoot_node[i], widget_node);
+ gtk_css_node_set_state (priv->overshoot_node[i], gtk_css_node_get_state (widget_node));
+ g_object_unref (priv->overshoot_node[i]);
+
+ priv->undershoot_node[i] = gtk_css_node_new ();
+ gtk_css_node_set_name (priv->undershoot_node[i], I_("undershoot"));
+ gtk_css_node_add_class (priv->undershoot_node[i], classes[i]);
+ gtk_css_node_set_parent (priv->undershoot_node[i], widget_node);
+ gtk_css_node_set_state (priv->undershoot_node[i], gtk_css_node_get_state (widget_node));
+ g_object_unref (priv->undershoot_node[i]);
+ }
+}
+
+/**
+ * gtk_scrolled_window_new:
+ * @hadjustment: (allow-none): horizontal adjustment
+ * @vadjustment: (allow-none): vertical adjustment
+ *
+ * Creates a new scrolled window.
+ *
+ * The two arguments are the scrolled window’s adjustments; these will be
+ * shared with the scrollbars and the child widget to keep the bars in sync
+ * with the child. Usually you want to pass %NULL for the adjustments, which
+ * will cause the scrolled window to create them for you.
+ *
+ * Returns: a new scrolled window
+ */
+GtkWidget*
+gtk_scrolled_window_new (GtkAdjustment *hadjustment,
+ GtkAdjustment *vadjustment)
+{
+ GtkWidget *scrolled_window;
+
+ if (hadjustment)
+ g_return_val_if_fail (GTK_IS_ADJUSTMENT (hadjustment), NULL);
+
+ if (vadjustment)
+ g_return_val_if_fail (GTK_IS_ADJUSTMENT (vadjustment), NULL);
+
+ scrolled_window = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
+ "hadjustment", hadjustment,
+ "vadjustment", vadjustment,
+ NULL);
+
+ return scrolled_window;
+}
+
+/**
+ * gtk_scrolled_window_set_hadjustment:
+ * @scrolled_window: a #GtkScrolledWindow
+ * @hadjustment: horizontal scroll adjustment
+ *
+ * Sets the #GtkAdjustment for the horizontal scrollbar.
+ */
+void
+gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
+ GtkAdjustment *hadjustment)
+{
+ GtkScrolledWindowPrivate *priv;
+ GtkBin *bin;
+ GtkWidget *child;
+
+ g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
+ if (hadjustment)
+ g_return_if_fail (GTK_IS_ADJUSTMENT (hadjustment));
+ else
+ hadjustment = (GtkAdjustment*) g_object_new (GTK_TYPE_ADJUSTMENT, NULL);
+
+ bin = GTK_BIN (scrolled_window);
+ priv = scrolled_window->priv;
+
+ if (!priv->hscrollbar)
+ {
+ priv->hscrollbar = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, hadjustment);
+
+ gtk_widget_set_parent (priv->hscrollbar, GTK_WIDGET (scrolled_window));
+ g_object_ref (priv->hscrollbar);
+ gtk_widget_show (priv->hscrollbar);
+ update_scrollbar_positions (scrolled_window);
+ }
+ else
+ {
+ GtkAdjustment *old_adjustment;
+
+ old_adjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
+ if (old_adjustment == hadjustment)
+ return;
+
+ g_signal_handlers_disconnect_by_func (old_adjustment,
+ gtk_scrolled_window_adjustment_changed,
+ scrolled_window);
+ gtk_adjustment_enable_animation (old_adjustment, NULL, 0);
+ gtk_range_set_adjustment (GTK_RANGE (priv->hscrollbar), hadjustment);
+ }
+ hadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
+ g_signal_connect (hadjustment,
+ "changed",
+ G_CALLBACK (gtk_scrolled_window_adjustment_changed),
+ scrolled_window);
+ g_signal_connect (hadjustment,
+ "value-changed",
+ G_CALLBACK (gtk_scrolled_window_adjustment_value_changed),
+ scrolled_window);
+ gtk_scrolled_window_adjustment_changed (hadjustment, scrolled_window);
+ gtk_scrolled_window_adjustment_value_changed (hadjustment, scrolled_window);
+
+ child = gtk_bin_get_child (bin);
+ if (GTK_IS_SCROLLABLE (child))
+ gtk_scrollable_set_hadjustment (GTK_SCROLLABLE (child), hadjustment);
+
+ if (gtk_scrolled_window_should_animate (scrolled_window))
+ gtk_adjustment_enable_animation (hadjustment, gtk_widget_get_frame_clock (GTK_WIDGET (scrolled_window)), ANIMATION_DURATION);
+ g_object_notify_by_pspec (G_OBJECT (scrolled_window), properties[PROP_HADJUSTMENT]);
+}
+
+/**
+ * gtk_scrolled_window_set_vadjustment:
+ * @scrolled_window: a #GtkScrolledWindow
+ * @vadjustment: vertical scroll adjustment
+ *
+ * Sets the #GtkAdjustment for the vertical scrollbar.
+ */
+void
+gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
+ GtkAdjustment *vadjustment)
+{
+ GtkScrolledWindowPrivate *priv;
+ GtkBin *bin;
+ GtkWidget *child;
+
+ g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
+ if (vadjustment)
+ g_return_if_fail (GTK_IS_ADJUSTMENT (vadjustment));
else
vadjustment = (GtkAdjustment*) g_object_new (GTK_TYPE_ADJUSTMENT, NULL);
g_clear_object (&priv->drag_gesture);
g_clear_object (&priv->swipe_gesture);
g_clear_object (&priv->long_press_gesture);
+ g_clear_object (&priv->gadget);
g_clear_pointer (&priv->scroll_history, (GDestroyNotify) g_array_unref);
GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->destroy (widget);
}
}
-static void
-gtk_scrolled_window_draw_scrollbars_junction (GtkScrolledWindow *scrolled_window,
- cairo_t *cr)
-{
- GtkScrolledWindowPrivate *priv = scrolled_window->priv;
- GtkWidget *widget = GTK_WIDGET (scrolled_window);
- GtkAllocation hscr_allocation, vscr_allocation;
- GtkStyleContext *context;
- GdkRectangle junction_rect;
- gboolean is_rtl;
-
- is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
- gtk_widget_get_allocation (GTK_WIDGET (priv->hscrollbar), &hscr_allocation);
- gtk_widget_get_allocation (GTK_WIDGET (priv->vscrollbar), &vscr_allocation);
-
- context = gtk_widget_get_style_context (widget);
-
- if (priv->shadow_type != GTK_SHADOW_NONE)
- {
- GtkStateFlags state;
- GtkBorder padding, border;
-
- state = gtk_style_context_get_state (context);
-
- gtk_style_context_get_padding (context, state, &padding);
- gtk_style_context_get_border (context, state, &border);
-
- junction_rect.x = padding.left + border.left;
- junction_rect.y = padding.top + border.top;
- }
- else
- {
- junction_rect.x = 0;
- junction_rect.y = 0;
- }
-
- junction_rect.width = vscr_allocation.width;
- junction_rect.height = hscr_allocation.height;
-
- if ((is_rtl &&
- (priv->window_placement == GTK_CORNER_TOP_RIGHT ||
- priv->window_placement == GTK_CORNER_BOTTOM_RIGHT)) ||
- (!is_rtl &&
- (priv->window_placement == GTK_CORNER_TOP_LEFT ||
- priv->window_placement == GTK_CORNER_BOTTOM_LEFT)))
- junction_rect.x += hscr_allocation.width;
-
- if (priv->window_placement == GTK_CORNER_TOP_LEFT ||
- priv->window_placement == GTK_CORNER_TOP_RIGHT)
- junction_rect.y += vscr_allocation.height;
-
- gtk_style_context_save_named (context, "junction");
-
- gtk_render_background (context, cr,
- junction_rect.x, junction_rect.y,
- junction_rect.width, junction_rect.height);
- gtk_render_frame (context, cr,
- junction_rect.x, junction_rect.y,
- junction_rect.width, junction_rect.height);
-
- gtk_style_context_restore (context);
-}
-
-static void
-gtk_scrolled_window_inner_allocation (GtkWidget *widget,
- GtkAllocation *rect)
-{
- GtkWidget *child;
- GtkBorder border = { 0 };
-
- gtk_scrolled_window_relative_allocation (widget, rect);
-
- child = gtk_bin_get_child (GTK_BIN (widget));
- if (GTK_IS_SCROLLABLE (child) &&
- gtk_scrollable_get_border (GTK_SCROLLABLE (child), &border))
- {
- rect->x += border.left;
- rect->y += border.top;
- rect->width -= border.left + border.right;
- rect->height -= border.top + border.bottom;
- }
-}
-
-static void
-gtk_scrolled_window_draw_overshoot (GtkScrolledWindow *scrolled_window,
- cairo_t *cr)
-{
- GtkScrolledWindowPrivate *priv = scrolled_window->priv;
- GtkWidget *widget = GTK_WIDGET (scrolled_window);
- gint overshoot_x, overshoot_y;
- GtkStyleContext *context;
- GdkRectangle rect;
-
- if (!_gtk_scrolled_window_get_overshoot (scrolled_window, &overshoot_x, &overshoot_y))
- return;
-
- context = gtk_widget_get_style_context (widget);
- gtk_scrolled_window_inner_allocation (widget, &rect);
-
- overshoot_x = CLAMP (overshoot_x, - MAX_OVERSHOOT_DISTANCE, MAX_OVERSHOOT_DISTANCE);
- overshoot_y = CLAMP (overshoot_y, - MAX_OVERSHOOT_DISTANCE, MAX_OVERSHOOT_DISTANCE);
-
- if (overshoot_x > 0)
- {
- gtk_style_context_save_to_node (context, priv->overshoot_node[GTK_POS_RIGHT]);
- gtk_render_background (context, cr, rect.x + rect.width - overshoot_x, rect.y, overshoot_x, rect.height);
- gtk_render_frame (context, cr, rect.x + rect.width - overshoot_x, rect.y, overshoot_x, rect.height);
- gtk_style_context_restore (context);
- }
- else if (overshoot_x < 0)
- {
- gtk_style_context_save_to_node (context, priv->overshoot_node[GTK_POS_LEFT]);
- gtk_render_background (context, cr, rect.x, rect.y, -overshoot_x, rect.height);
- gtk_render_frame (context, cr, rect.x, rect.y, -overshoot_x, rect.height);
- gtk_style_context_restore (context);
- }
-
- if (overshoot_y > 0)
- {
- gtk_style_context_save_to_node (context, priv->overshoot_node[GTK_POS_BOTTOM]);
- gtk_render_background (context, cr, rect.x, rect.y + rect.height - overshoot_y, rect.width, overshoot_y);
- gtk_render_frame (context, cr, rect.x, rect.y + rect.height - overshoot_y, rect.width, overshoot_y);
- gtk_style_context_restore (context);
- }
- else if (overshoot_y < 0)
- {
- gtk_style_context_save_to_node (context, priv->overshoot_node[GTK_POS_TOP]);
- gtk_render_background (context, cr, rect.x, rect.y, rect.width, -overshoot_y);
- gtk_render_frame (context, cr, rect.x, rect.y, rect.width, -overshoot_y);
- gtk_style_context_restore (context);
- }
-}
-
-static void
-gtk_scrolled_window_draw_undershoot (GtkScrolledWindow *scrolled_window,
- cairo_t *cr)
-{
- GtkScrolledWindowPrivate *priv = scrolled_window->priv;
- GtkWidget *widget = GTK_WIDGET (scrolled_window);
- GtkStyleContext *context;
- GdkRectangle rect;
- GtkAdjustment *adj;
-
- context = gtk_widget_get_style_context (widget);
- gtk_scrolled_window_inner_allocation (widget, &rect);
-
- adj = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
- if (gtk_adjustment_get_value (adj) < gtk_adjustment_get_upper (adj) - gtk_adjustment_get_page_size (adj))
- {
- gtk_style_context_save_to_node (context, priv->undershoot_node[GTK_POS_RIGHT]);
- gtk_render_background (context, cr, rect.x + rect.width - UNDERSHOOT_SIZE, rect.y, UNDERSHOOT_SIZE, rect.height);
- gtk_render_frame (context, cr, rect.x + rect.width - UNDERSHOOT_SIZE, rect.y, UNDERSHOOT_SIZE, rect.height);
+static void
+gtk_scrolled_window_inner_allocation (GtkWidget *widget,
+ GtkAllocation *rect)
+{
+ GtkWidget *child;
+ GtkBorder border = { 0 };
- gtk_style_context_restore (context);
- }
- if (gtk_adjustment_get_value (adj) > gtk_adjustment_get_lower (adj))
- {
- gtk_style_context_save_to_node (context, priv->undershoot_node[GTK_POS_LEFT]);
- gtk_render_background (context, cr, rect.x, rect.y, UNDERSHOOT_SIZE, rect.height);
- gtk_render_frame (context, cr, rect.x, rect.y, UNDERSHOOT_SIZE, rect.height);
- gtk_style_context_restore (context);
- }
+ gtk_scrolled_window_relative_allocation (widget, rect);
- adj = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
- if (gtk_adjustment_get_value (adj) < gtk_adjustment_get_upper (adj) - gtk_adjustment_get_page_size (adj))
- {
- gtk_style_context_save_to_node (context, priv->undershoot_node[GTK_POS_BOTTOM]);
- gtk_render_background (context, cr, rect.x, rect.y + rect.height - UNDERSHOOT_SIZE, rect.width, UNDERSHOOT_SIZE);
- gtk_render_frame (context, cr, rect.x, rect.y + rect.height - UNDERSHOOT_SIZE, rect.width, UNDERSHOOT_SIZE);
- gtk_style_context_restore (context);
- }
- if (gtk_adjustment_get_value (adj) > gtk_adjustment_get_lower (adj))
+ child = gtk_bin_get_child (GTK_BIN (widget));
+ if (GTK_IS_SCROLLABLE (child) &&
+ gtk_scrollable_get_border (GTK_SCROLLABLE (child), &border))
{
- gtk_style_context_save_to_node (context, priv->undershoot_node[GTK_POS_TOP]);
- gtk_render_background (context, cr, rect.x, rect.y, rect.width, UNDERSHOOT_SIZE);
- gtk_render_frame (context, cr, rect.x, rect.y, rect.width, UNDERSHOOT_SIZE);
- gtk_style_context_restore (context);
+ rect->x += border.left;
+ rect->y += border.top;
+ rect->width -= border.left + border.right;
+ rect->height -= border.top + border.bottom;
}
}
{
GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
GtkScrolledWindowPrivate *priv = scrolled_window->priv;
- GtkStyleContext *context;
-
- if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget)))
- {
- context = gtk_widget_get_style_context (widget);
-
- gtk_render_background (context, cr,
- 0, 0,
- gtk_widget_get_allocated_width (widget),
- gtk_widget_get_allocated_height (widget));
- gtk_render_frame (context, cr,
- 0, 0,
- gtk_widget_get_allocated_width (widget),
- gtk_widget_get_allocated_height (widget));
-
- if (priv->hscrollbar_visible &&
- priv->vscrollbar_visible)
- gtk_scrolled_window_draw_scrollbars_junction (scrolled_window, cr);
- }
- GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->draw (widget, cr);
-
- if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget)))
- {
- gtk_scrolled_window_draw_undershoot (scrolled_window, cr);
- gtk_scrolled_window_draw_overshoot (scrolled_window, cr);
- }
+ gtk_css_gadget_draw (priv->gadget, cr);
return FALSE;
}
gtk_scrolled_window_relative_allocation (GtkWidget *widget,
GtkAllocation *allocation)
{
- GtkAllocation widget_allocation;
+ GtkAllocation content_allocation;
GtkScrolledWindow *scrolled_window;
GtkScrolledWindowPrivate *priv;
gint sb_spacing;
gtk_widget_get_preferred_height (priv->hscrollbar, &sb_height, NULL);
gtk_widget_get_preferred_width (priv->vscrollbar, &sb_width, NULL);
- gtk_widget_get_allocation (widget, &widget_allocation);
-
- allocation->x = 0;
- allocation->y = 0;
- allocation->width = widget_allocation.width;
- allocation->height = widget_allocation.height;
-
- /* Subtract some things from our available allocation size */
- if (priv->shadow_type != GTK_SHADOW_NONE)
- {
- GtkStyleContext *context;
- GtkStateFlags state;
- GtkBorder padding, border;
-
- context = gtk_widget_get_style_context (widget);
- state = gtk_style_context_get_state (context);
-
- gtk_style_context_get_border (context, state, &border);
- gtk_style_context_get_padding (context, state, &padding);
-
- allocation->x += padding.left + border.left;
- allocation->y += padding.top + border.top;
- allocation->width = MAX (1, allocation->width - (padding.left + border.left + padding.right + border.right));
- allocation->height = MAX (1, allocation->height - (padding.top + border.top + padding.bottom + border.bottom));
- }
-
- if (priv->vscrollbar_visible && !priv->use_indicators)
- {
- gboolean is_rtl;
-
- is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
-
- if ((!is_rtl &&
- (priv->window_placement == GTK_CORNER_TOP_RIGHT ||
- priv->window_placement == GTK_CORNER_BOTTOM_RIGHT)) ||
- (is_rtl &&
- (priv->window_placement == GTK_CORNER_TOP_LEFT ||
- priv->window_placement == GTK_CORNER_BOTTOM_LEFT)))
- allocation->x += (sb_width + sb_spacing);
-
- allocation->width = MAX (1, allocation->width - (sb_width + sb_spacing));
- }
-
- if (priv->hscrollbar_visible && !priv->use_indicators)
- {
-
- if (priv->window_placement == GTK_CORNER_BOTTOM_LEFT ||
- priv->window_placement == GTK_CORNER_BOTTOM_RIGHT)
- allocation->y += (sb_height + sb_spacing);
-
- allocation->height = MAX (1, allocation->height - (sb_height + sb_spacing));
- }
-}
-
-static gboolean
-_gtk_scrolled_window_get_overshoot (GtkScrolledWindow *scrolled_window,
- gint *overshoot_x,
- gint *overshoot_y)
-{
- GtkScrolledWindowPrivate *priv = scrolled_window->priv;
- GtkAdjustment *vadjustment, *hadjustment;
- gdouble lower, upper, x, y;
-
- /* Vertical overshoot */
- vadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
- lower = gtk_adjustment_get_lower (vadjustment);
- upper = gtk_adjustment_get_upper (vadjustment) -
- gtk_adjustment_get_page_size (vadjustment);
-
- if (priv->unclamped_vadj_value < lower)
- y = priv->unclamped_vadj_value - lower;
- else if (priv->unclamped_vadj_value > upper)
- y = priv->unclamped_vadj_value - upper;
- else
- y = 0;
-
- /* Horizontal overshoot */
- hadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
- lower = gtk_adjustment_get_lower (hadjustment);
- upper = gtk_adjustment_get_upper (hadjustment) -
- gtk_adjustment_get_page_size (hadjustment);
-
- if (priv->unclamped_hadj_value < lower)
- x = priv->unclamped_hadj_value - lower;
- else if (priv->unclamped_hadj_value > upper)
- x = priv->unclamped_hadj_value - upper;
- else
- x = 0;
-
- if (overshoot_x)
- *overshoot_x = x;
-
- if (overshoot_y)
- *overshoot_y = y;
-
- return (x != 0 || y != 0);
-}
-
-static void
-gtk_scrolled_window_allocate_child (GtkScrolledWindow *swindow,
- GtkAllocation *relative_allocation)
-{
- GtkWidget *widget = GTK_WIDGET (swindow), *child;
- GtkAllocation child_allocation;
-
- child = gtk_bin_get_child (GTK_BIN (widget));
-
- gtk_scrolled_window_relative_allocation (widget, relative_allocation);
-
- child_allocation.x = relative_allocation->x;
- child_allocation.y = relative_allocation->y;
- child_allocation.width = relative_allocation->width;
- child_allocation.height = relative_allocation->height;
-
- gtk_widget_size_allocate (child, &child_allocation);
-}
-
-static void
-gtk_scrolled_window_allocate_scrollbar (GtkScrolledWindow *scrolled_window,
- GtkWidget *scrollbar,
- GtkAllocation *allocation)
-{
- GtkAllocation child_allocation, content_allocation;
- GtkWidget *widget = GTK_WIDGET (scrolled_window);
- gint sb_spacing, sb_height, sb_width;
- GtkScrolledWindowPrivate *priv;
-
- priv = scrolled_window->priv;
-
- gtk_scrolled_window_inner_allocation (widget, &content_allocation);
- sb_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
- gtk_widget_get_preferred_height (priv->hscrollbar, &sb_height, NULL);
- gtk_widget_get_preferred_width (priv->vscrollbar, &sb_width, NULL);
-
- if (scrollbar == priv->hscrollbar)
- {
- child_allocation.x = content_allocation.x;
-
- if (priv->window_placement == GTK_CORNER_TOP_LEFT ||
- priv->window_placement == GTK_CORNER_TOP_RIGHT)
- {
- if (priv->use_indicators)
- child_allocation.y = content_allocation.y + content_allocation.height - sb_height;
- else
- child_allocation.y = content_allocation.y + content_allocation.height + sb_spacing;
- }
- else
- {
- if (priv->use_indicators)
- child_allocation.y = content_allocation.y;
- else
- child_allocation.y = content_allocation.y - sb_spacing - sb_height;
- }
-
- child_allocation.width = content_allocation.width;
- child_allocation.height = sb_height;
- }
- else if (scrollbar == priv->vscrollbar)
- {
- if ((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL &&
- (priv->window_placement == GTK_CORNER_TOP_RIGHT ||
- priv->window_placement == GTK_CORNER_BOTTOM_RIGHT)) ||
- (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR &&
- (priv->window_placement == GTK_CORNER_TOP_LEFT ||
- priv->window_placement == GTK_CORNER_BOTTOM_LEFT)))
- {
- if (priv->use_indicators)
- child_allocation.x = content_allocation.x + content_allocation.width - sb_width;
- else
- child_allocation.x = content_allocation.x + content_allocation.width + sb_spacing;
- }
- else
- {
- if (priv->use_indicators)
- child_allocation.x = content_allocation.x;
- else
- child_allocation.x = content_allocation.x - sb_spacing - sb_width;
- }
-
- child_allocation.y = content_allocation.y;
- child_allocation.width = sb_width;
- child_allocation.height = content_allocation.height;
- }
-
- *allocation = child_allocation;
-}
-
-static void
-gtk_scrolled_window_size_allocate (GtkWidget *widget,
- GtkAllocation *allocation)
-{
- GtkScrolledWindow *scrolled_window;
- GtkScrolledWindowPrivate *priv;
- GtkBin *bin;
- GtkAllocation relative_allocation;
- GtkAllocation child_allocation;
- GtkWidget *child;
- gint sb_spacing;
- gint sb_width;
- gint sb_height;
-
- scrolled_window = GTK_SCROLLED_WINDOW (widget);
- bin = GTK_BIN (scrolled_window);
- priv = scrolled_window->priv;
-
- if (gtk_widget_get_realized (widget))
- {
- gdk_window_move_resize (gtk_widget_get_window (widget),
- allocation->x, allocation->y,
- allocation->width, allocation->height);
- }
-
- /* Get possible scrollbar dimensions */
- sb_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
- gtk_widget_get_preferred_height (priv->hscrollbar, &sb_height, NULL);
- gtk_widget_get_preferred_width (priv->vscrollbar, &sb_width, NULL);
-
- gtk_widget_set_allocation (widget, allocation);
-
- if (priv->hscrollbar_policy == GTK_POLICY_ALWAYS)
- priv->hscrollbar_visible = TRUE;
- else if (priv->hscrollbar_policy == GTK_POLICY_NEVER ||
- priv->hscrollbar_policy == GTK_POLICY_EXTERNAL)
- priv->hscrollbar_visible = FALSE;
+ gtk_css_gadget_get_content_allocation (priv->gadget, &content_allocation,
+ NULL);
- if (priv->vscrollbar_policy == GTK_POLICY_ALWAYS)
- priv->vscrollbar_visible = TRUE;
- else if (priv->vscrollbar_policy == GTK_POLICY_NEVER ||
- priv->vscrollbar_policy == GTK_POLICY_EXTERNAL)
- priv->vscrollbar_visible = FALSE;
+ allocation->x = content_allocation.x;
+ allocation->y = content_allocation.y;
+ allocation->width = content_allocation.width;
+ allocation->height = content_allocation.height;
- child = gtk_bin_get_child (bin);
- if (child && gtk_widget_get_visible (child))
+ /* Subtract some things from our available allocation size */
+ if (priv->vscrollbar_visible && !priv->use_indicators)
{
- gint child_scroll_width;
- gint child_scroll_height;
- GtkScrollablePolicy hscroll_policy;
- GtkScrollablePolicy vscroll_policy;
- gboolean previous_hvis;
- gboolean previous_vvis;
- guint count = 0;
+ gboolean is_rtl;
- hscroll_policy = GTK_IS_SCROLLABLE (child)
- ? gtk_scrollable_get_hscroll_policy (GTK_SCROLLABLE (child))
- : GTK_SCROLL_MINIMUM;
- vscroll_policy = GTK_IS_SCROLLABLE (child)
- ? gtk_scrollable_get_vscroll_policy (GTK_SCROLLABLE (child))
- : GTK_SCROLL_MINIMUM;
+ is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
- /* Determine scrollbar visibility first via hfw apis */
- if (gtk_widget_get_request_mode (child) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
- {
- if (hscroll_policy == GTK_SCROLL_MINIMUM)
- gtk_widget_get_preferred_width (child, &child_scroll_width, NULL);
- else
- gtk_widget_get_preferred_width (child, NULL, &child_scroll_width);
+ if ((!is_rtl &&
+ (priv->window_placement == GTK_CORNER_TOP_RIGHT ||
+ priv->window_placement == GTK_CORNER_BOTTOM_RIGHT)) ||
+ (is_rtl &&
+ (priv->window_placement == GTK_CORNER_TOP_LEFT ||
+ priv->window_placement == GTK_CORNER_BOTTOM_LEFT)))
+ allocation->x += (sb_width + sb_spacing);
- if (priv->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
- {
- /* First try without a vertical scrollbar if the content will fit the height
- * given the extra width of the scrollbar */
- if (vscroll_policy == GTK_SCROLL_MINIMUM)
- gtk_widget_get_preferred_height_for_width (child,
- MAX (allocation->width, child_scroll_width),
- &child_scroll_height, NULL);
- else
- gtk_widget_get_preferred_height_for_width (child,
- MAX (allocation->width, child_scroll_width),
- NULL, &child_scroll_height);
+ allocation->width = MAX (1, allocation->width - (sb_width + sb_spacing));
+ }
- if (priv->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
- {
- /* Does the content height fit the allocation height ? */
- priv->vscrollbar_visible = child_scroll_height > allocation->height;
+ if (priv->hscrollbar_visible && !priv->use_indicators)
+ {
- /* Does the content width fit the allocation with minus a possible scrollbar ? */
- priv->hscrollbar_visible =
- child_scroll_width > allocation->width -
- (priv->vscrollbar_visible && !priv->use_indicators ? sb_width + sb_spacing : 0);
+ if (priv->window_placement == GTK_CORNER_BOTTOM_LEFT ||
+ priv->window_placement == GTK_CORNER_BOTTOM_RIGHT)
+ allocation->y += (sb_height + sb_spacing);
- /* Now that we've guessed the hscrollbar, does the content height fit
- * the possible new allocation height ?
- */
- priv->vscrollbar_visible =
- child_scroll_height > allocation->height -
- (priv->hscrollbar_visible && !priv->use_indicators ? sb_height + sb_spacing : 0);
+ allocation->height = MAX (1, allocation->height - (sb_height + sb_spacing));
+ }
+}
- /* Now that we've guessed the vscrollbar, does the content width fit
- * the possible new allocation width ?
- */
- priv->hscrollbar_visible =
- child_scroll_width > allocation->width -
- (priv->vscrollbar_visible && !priv->use_indicators ? sb_width + sb_spacing : 0);
- }
- else /* priv->hscrollbar_policy != GTK_POLICY_AUTOMATIC */
- {
- priv->hscrollbar_visible = policy_may_be_visible (priv->hscrollbar_policy);
- priv->vscrollbar_visible = child_scroll_height > allocation->height -
- (priv->hscrollbar_visible && !priv->use_indicators ? sb_height + sb_spacing : 0);
- }
- }
- else /* priv->vscrollbar_policy != GTK_POLICY_AUTOMATIC */
- {
- priv->vscrollbar_visible = policy_may_be_visible (priv->vscrollbar_policy);
+static gboolean
+_gtk_scrolled_window_get_overshoot (GtkScrolledWindow *scrolled_window,
+ gint *overshoot_x,
+ gint *overshoot_y)
+{
+ GtkScrolledWindowPrivate *priv = scrolled_window->priv;
+ GtkAdjustment *vadjustment, *hadjustment;
+ gdouble lower, upper, x, y;
- if (priv->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
- priv->hscrollbar_visible =
- child_scroll_width > allocation->width -
- (priv->vscrollbar_visible && !priv->use_indicators ? 0 : sb_width + sb_spacing);
- else
- priv->hscrollbar_visible = policy_may_be_visible (priv->hscrollbar_policy);
- }
- }
- else /* GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT */
- {
- if (vscroll_policy == GTK_SCROLL_MINIMUM)
- gtk_widget_get_preferred_height (child, &child_scroll_height, NULL);
- else
- gtk_widget_get_preferred_height (child, NULL, &child_scroll_height);
+ /* Vertical overshoot */
+ vadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
+ lower = gtk_adjustment_get_lower (vadjustment);
+ upper = gtk_adjustment_get_upper (vadjustment) -
+ gtk_adjustment_get_page_size (vadjustment);
- if (priv->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
- {
- /* First try without a horizontal scrollbar if the content will fit the width
- * given the extra height of the scrollbar */
- if (hscroll_policy == GTK_SCROLL_MINIMUM)
- gtk_widget_get_preferred_width_for_height (child,
- MAX (allocation->height, child_scroll_height),
- &child_scroll_width, NULL);
- else
- gtk_widget_get_preferred_width_for_height (child,
- MAX (allocation->height, child_scroll_height),
- NULL, &child_scroll_width);
+ if (priv->unclamped_vadj_value < lower)
+ y = priv->unclamped_vadj_value - lower;
+ else if (priv->unclamped_vadj_value > upper)
+ y = priv->unclamped_vadj_value - upper;
+ else
+ y = 0;
- if (priv->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
- {
- /* Does the content width fit the allocation width ? */
- priv->hscrollbar_visible = child_scroll_width > allocation->width;
+ /* Horizontal overshoot */
+ hadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
+ lower = gtk_adjustment_get_lower (hadjustment);
+ upper = gtk_adjustment_get_upper (hadjustment) -
+ gtk_adjustment_get_page_size (hadjustment);
- /* Does the content height fit the allocation with minus a possible scrollbar ? */
- priv->vscrollbar_visible =
- child_scroll_height > allocation->height -
- (priv->hscrollbar_visible && !priv->use_indicators ? sb_height + sb_spacing : 0);
+ if (priv->unclamped_hadj_value < lower)
+ x = priv->unclamped_hadj_value - lower;
+ else if (priv->unclamped_hadj_value > upper)
+ x = priv->unclamped_hadj_value - upper;
+ else
+ x = 0;
- /* Now that we've guessed the vscrollbar, does the content width fit
- * the possible new allocation width ?
- */
- priv->hscrollbar_visible =
- child_scroll_width > allocation->width -
- (priv->vscrollbar_visible && !priv->use_indicators ? sb_width + sb_spacing : 0);
+ if (overshoot_x)
+ *overshoot_x = x;
- /* Now that we've guessed the hscrollbar, does the content height fit
- * the possible new allocation height ?
- */
- priv->vscrollbar_visible =
- child_scroll_height > allocation->height -
- (priv->hscrollbar_visible && !priv->use_indicators ? sb_height + sb_spacing : 0);
- }
- else /* priv->vscrollbar_policy != GTK_POLICY_AUTOMATIC */
- {
- priv->vscrollbar_visible = policy_may_be_visible (priv->vscrollbar_policy);
- priv->hscrollbar_visible = child_scroll_width > allocation->width -
- (priv->vscrollbar_visible && !priv->use_indicators ? sb_width + sb_spacing : 0);
- }
- }
- else /* priv->hscrollbar_policy != GTK_POLICY_AUTOMATIC */
- {
- priv->hscrollbar_visible = policy_may_be_visible (priv->hscrollbar_policy);
+ if (overshoot_y)
+ *overshoot_y = y;
- if (priv->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
- priv->vscrollbar_visible =
- child_scroll_height > allocation->height -
- (priv->hscrollbar_visible && !priv->use_indicators ? sb_height + sb_spacing : 0);
- else
- priv->vscrollbar_visible = policy_may_be_visible (priv->vscrollbar_policy);
- }
- }
+ return (x != 0 || y != 0);
+}
- /* Now after guessing scrollbar visibility; fall back on the allocation loop which
- * observes the adjustments to detect scrollbar visibility and also avoids
- * infinite recursion
- */
- do
- {
- previous_hvis = priv->hscrollbar_visible;
- previous_vvis = priv->vscrollbar_visible;
- gtk_scrolled_window_allocate_child (scrolled_window, &relative_allocation);
+static void
+gtk_scrolled_window_allocate_child (GtkScrolledWindow *swindow,
+ GtkAllocation *relative_allocation)
+{
+ GtkWidget *widget = GTK_WIDGET (swindow), *child;
+ GtkAllocation child_allocation;
- /* Explicitly force scrollbar visibility checks.
- *
- * Since we make a guess above, the child might not decide to update the adjustments
- * if they logically did not change since the last configuration
- */
- if (priv->hscrollbar)
- gtk_scrolled_window_adjustment_changed
- (gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)), scrolled_window);
+ child = gtk_bin_get_child (GTK_BIN (widget));
- if (priv->vscrollbar)
- gtk_scrolled_window_adjustment_changed
- (gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)), scrolled_window);
+ gtk_scrolled_window_relative_allocation (widget, relative_allocation);
- /* If, after the first iteration, the hscrollbar and the
- * vscrollbar flip visiblity... or if one of the scrollbars flip
- * on each itteration indefinitly/infinitely, then we just need both
- * at this size.
- */
- if ((count &&
- previous_hvis != priv->hscrollbar_visible &&
- previous_vvis != priv->vscrollbar_visible) || count > 3)
- {
- priv->hscrollbar_visible = TRUE;
- priv->vscrollbar_visible = TRUE;
+ child_allocation.x = relative_allocation->x;
+ child_allocation.y = relative_allocation->y;
+ child_allocation.width = relative_allocation->width;
+ child_allocation.height = relative_allocation->height;
- gtk_scrolled_window_allocate_child (scrolled_window, &relative_allocation);
+ gtk_widget_size_allocate (child, &child_allocation);
+}
- break;
- }
+static void
+gtk_scrolled_window_allocate_scrollbar (GtkScrolledWindow *scrolled_window,
+ GtkWidget *scrollbar,
+ GtkAllocation *allocation)
+{
+ GtkAllocation child_allocation, content_allocation;
+ GtkWidget *widget = GTK_WIDGET (scrolled_window);
+ gint sb_spacing, sb_height, sb_width;
+ GtkScrolledWindowPrivate *priv;
+
+ priv = scrolled_window->priv;
+
+ gtk_scrolled_window_inner_allocation (widget, &content_allocation);
+ sb_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
+ gtk_widget_get_preferred_height (priv->hscrollbar, &sb_height, NULL);
+ gtk_widget_get_preferred_width (priv->vscrollbar, &sb_width, NULL);
- count++;
- }
- while (previous_hvis != priv->hscrollbar_visible ||
- previous_vvis != priv->vscrollbar_visible);
- }
- else
+ if (scrollbar == priv->hscrollbar)
{
- priv->hscrollbar_visible = priv->hscrollbar_policy == GTK_POLICY_ALWAYS;
- priv->vscrollbar_visible = priv->vscrollbar_policy == GTK_POLICY_ALWAYS;
- gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
- }
+ child_allocation.x = content_allocation.x;
- gtk_widget_set_child_visible (priv->hscrollbar, priv->hscrollbar_visible);
- if (priv->hscrollbar_visible)
- {
- gtk_scrolled_window_allocate_scrollbar (scrolled_window,
- priv->hscrollbar,
- &child_allocation);
- if (priv->use_indicators)
+ if (priv->window_placement == GTK_CORNER_TOP_LEFT ||
+ priv->window_placement == GTK_CORNER_TOP_RIGHT)
{
- gdk_window_move_resize (priv->hindicator.window,
- child_allocation.x,
- child_allocation.y,
- child_allocation.width,
- child_allocation.height);
- child_allocation.x = 0;
- child_allocation.y = 0;
+ if (priv->use_indicators)
+ child_allocation.y = content_allocation.y + content_allocation.height - sb_height;
+ else
+ child_allocation.y = content_allocation.y + content_allocation.height + sb_spacing;
+ }
+ else
+ {
+ if (priv->use_indicators)
+ child_allocation.y = content_allocation.y;
+ else
+ child_allocation.y = content_allocation.y - sb_spacing - sb_height;
}
- gtk_widget_size_allocate (priv->hscrollbar, &child_allocation);
- }
- gtk_widget_set_child_visible (priv->vscrollbar, priv->vscrollbar_visible);
- if (priv->vscrollbar_visible)
+ child_allocation.width = content_allocation.width;
+ child_allocation.height = sb_height;
+ }
+ else if (scrollbar == priv->vscrollbar)
{
- gtk_scrolled_window_allocate_scrollbar (scrolled_window,
- priv->vscrollbar,
- &child_allocation);
- if (priv->use_indicators)
+ if ((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL &&
+ (priv->window_placement == GTK_CORNER_TOP_RIGHT ||
+ priv->window_placement == GTK_CORNER_BOTTOM_RIGHT)) ||
+ (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR &&
+ (priv->window_placement == GTK_CORNER_TOP_LEFT ||
+ priv->window_placement == GTK_CORNER_BOTTOM_LEFT)))
{
- gdk_window_move_resize (priv->vindicator.window,
- child_allocation.x,
- child_allocation.y,
- child_allocation.width,
- child_allocation.height);
- child_allocation.x = 0;
- child_allocation.y = 0;
+ if (priv->use_indicators)
+ child_allocation.x = content_allocation.x + content_allocation.width - sb_width;
+ else
+ child_allocation.x = content_allocation.x + content_allocation.width + sb_spacing;
}
- gtk_widget_size_allocate (priv->vscrollbar, &child_allocation);
+ else
+ {
+ if (priv->use_indicators)
+ child_allocation.x = content_allocation.x;
+ else
+ child_allocation.x = content_allocation.x - sb_spacing - sb_width;
+ }
+
+ child_allocation.y = content_allocation.y;
+ child_allocation.width = sb_width;
+ child_allocation.height = content_allocation.height;
}
- gtk_scrolled_window_check_attach_pan_gesture (scrolled_window);
+ *allocation = child_allocation;
+}
+
+static void
+gtk_scrolled_window_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GtkScrolledWindow *scrolled_window;
+ GtkScrolledWindowPrivate *priv;
+ GtkAllocation clip, content_allocation;
+
+ scrolled_window = GTK_SCROLLED_WINDOW (widget);
+ priv = scrolled_window->priv;
+
+ gtk_widget_set_allocation (widget, allocation);
+
+ if (gtk_widget_get_realized (widget))
+ gdk_window_move_resize (gtk_widget_get_window (widget),
+ allocation->x, allocation->y,
+ allocation->width, allocation->height);
+
+ content_allocation = *allocation;
+ content_allocation.x = content_allocation.y = 0;
+ gtk_css_gadget_allocate (priv->gadget,
+ &content_allocation,
+ gtk_widget_get_allocated_baseline (widget),
+ &clip);
+
+ clip.x += allocation->x;
+ clip.y += allocation->y;
+ gtk_widget_set_clip (widget, &clip);
}
static gboolean
gtk_container_add (GTK_CONTAINER (viewport), child);
}
-/*
- * _gtk_scrolled_window_get_spacing:
- * @scrolled_window: a scrolled window
- *
- * Gets the spacing between the scrolled window’s scrollbars and
- * the scrolled widget. Used by GtkCombo
- *
- * Returns: the spacing, in pixels.
- */
-static gint
-_gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window)
-{
- GtkScrolledWindowClass *class;
-
- g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), 0);
-
- class = GTK_SCROLLED_WINDOW_GET_CLASS (scrolled_window);
-
- if (class->scrollbar_spacing >= 0)
- return class->scrollbar_spacing;
- else
- {
- gint scrollbar_spacing;
-
- gtk_widget_style_get (GTK_WIDGET (scrolled_window),
- "scrollbar-spacing", &scrollbar_spacing,
- NULL);
-
- return scrollbar_spacing;
- }
-}
-
-static void
-gtk_scrolled_window_get_preferred_size (GtkWidget *widget,
- GtkOrientation orientation,
- gint *minimum_size,
- gint *natural_size)
-{
- GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
- GtkScrolledWindowPrivate *priv = scrolled_window->priv;
- GtkBin *bin = GTK_BIN (scrolled_window);
- gint extra_width;
- gint extra_height;
- gint scrollbar_spacing;
- GtkRequisition hscrollbar_requisition;
- GtkRequisition vscrollbar_requisition;
- GtkRequisition minimum_req, natural_req;
- GtkWidget *child;
- gint min_child_size, nat_child_size;
-
- scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
-
- extra_width = 0;
- extra_height = 0;
- minimum_req.width = 0;
- minimum_req.height = 0;
- natural_req.width = 0;
- natural_req.height = 0;
-
- gtk_widget_get_preferred_size (priv->hscrollbar,
- &hscrollbar_requisition, NULL);
- gtk_widget_get_preferred_size (priv->vscrollbar,
- &vscrollbar_requisition, NULL);
-
- child = gtk_bin_get_child (bin);
- if (child && gtk_widget_get_visible (child))
- {
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- gtk_widget_get_preferred_width (child,
- &min_child_size,
- &nat_child_size);
-
- if (priv->hscrollbar_policy == GTK_POLICY_NEVER)
- {
- minimum_req.width += min_child_size;
- natural_req.width += nat_child_size;
- }
- else
- {
- if (priv->min_content_width >= 0)
- {
- minimum_req.width = MAX (minimum_req.width, priv->min_content_width);
- natural_req.width = MAX (natural_req.width, priv->min_content_width);
- extra_width = -1;
- }
- else if (policy_may_be_visible (priv->vscrollbar_policy) && !priv->use_indicators)
- {
- minimum_req.width += vscrollbar_requisition.width;
- natural_req.width += vscrollbar_requisition.width;
- }
- }
- }
- else /* GTK_ORIENTATION_VERTICAL */
- {
- gtk_widget_get_preferred_height (child,
- &min_child_size,
- &nat_child_size);
-
- if (priv->vscrollbar_policy == GTK_POLICY_NEVER)
- {
- minimum_req.height += min_child_size;
- natural_req.height += nat_child_size;
- }
- else
- {
- if (priv->min_content_height >= 0)
- {
- minimum_req.height = MAX (minimum_req.height, priv->min_content_height);
- natural_req.height = MAX (natural_req.height, priv->min_content_height);
- extra_height = -1;
- }
- else if (policy_may_be_visible (priv->vscrollbar_policy) && !priv->use_indicators)
- {
- minimum_req.height += vscrollbar_requisition.height;
- natural_req.height += vscrollbar_requisition.height;
- }
- }
- }
- }
-
- if (policy_may_be_visible (priv->hscrollbar_policy) && !priv->use_indicators)
- {
- minimum_req.width = MAX (minimum_req.width, hscrollbar_requisition.width);
- natural_req.width = MAX (natural_req.width, hscrollbar_requisition.width);
- if (!extra_height || priv->hscrollbar_policy == GTK_POLICY_ALWAYS)
- extra_height = scrollbar_spacing + hscrollbar_requisition.height;
- }
-
- if (policy_may_be_visible (priv->vscrollbar_policy) && !priv->use_indicators)
- {
- minimum_req.height = MAX (minimum_req.height, vscrollbar_requisition.height);
- natural_req.height = MAX (natural_req.height, vscrollbar_requisition.height);
- if (!extra_width || priv->vscrollbar_policy == GTK_POLICY_ALWAYS)
- extra_width = scrollbar_spacing + vscrollbar_requisition.width;
- }
-
- minimum_req.width += MAX (0, extra_width);
- minimum_req.height += MAX (0, extra_height);
- natural_req.width += MAX (0, extra_width);
- natural_req.height += MAX (0, extra_height);
-
- if (priv->shadow_type != GTK_SHADOW_NONE)
- {
- GtkStyleContext *context;
- GtkStateFlags state;
- GtkBorder padding, border;
-
- context = gtk_widget_get_style_context (GTK_WIDGET (widget));
- state = gtk_style_context_get_state (context);
-
- gtk_style_context_get_padding (context, state, &padding);
- gtk_style_context_get_border (context, state, &border);
-
- minimum_req.width += padding.left + padding.right + border.left + border.right;
- minimum_req.height += padding.top + padding.bottom + border.top + border.bottom;
- natural_req.width += padding.left + padding.right + border.left + border.right;
- natural_req.height += padding.top + padding.bottom + border.top + border.bottom;
- }
-
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- *minimum_size = minimum_req.width;
- *natural_size = natural_req.width;
- }
- else
- {
- *minimum_size = minimum_req.height;
- *natural_size = natural_req.height;
- }
-}
-
static void
gtk_scrolled_window_get_preferred_width (GtkWidget *widget,
gint *minimum_size,
gint *natural_size)
{
- gtk_scrolled_window_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
+ gtk_css_gadget_get_preferred_size (GTK_SCROLLED_WINDOW (widget)->priv->gadget,
+ GTK_ORIENTATION_HORIZONTAL,
+ -1,
+ minimum_size, natural_size,
+ NULL, NULL);
}
static void
gint *minimum_size,
gint *natural_size)
{
- gtk_scrolled_window_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
+ gtk_css_gadget_get_preferred_size (GTK_SCROLLED_WINDOW (widget)->priv->gadget,
+ GTK_ORIENTATION_VERTICAL,
+ -1,
+ minimum_size, natural_size,
+ NULL, NULL);
}
static void